package com.codingstudy.login.configuration;


import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.serializer.ToStringSerializer;
import com.alibaba.fastjson.serializer.ValueFilter;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.text.SimpleDateFormat;
import java.util.*;

import java.util.concurrent.ConcurrentHashMap;


/**
 * @Author: wangzhengsheng@supcon.com
 * @Create: 2021/7/20 14:46
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {

        // WebMvcConfigurerAdapter 这个类在SpringBoot2.0已过时，官方推荐直接实现WebMvcConfigurer 这个接口



    /**
     * 使用fastjson代替jackson
     * @param converters
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        /*
         先把JackSon的消息转换器删除.
         备注: (1)源码分析可知，返回json的过程为:
               Controller调用结束后返回一个数据对象，for循环遍历conventers，找到支持application/json的HttpMessageConverter，然后将返回的数据序列化成json。
               具体参考org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor的writeWithMessageConverters方法
               (2)由于是list结构，我们添加的fastjson在最后。因此必须要将jackson的转换器删除，不然会先匹配上jackson，导致没使用fastjson
        */
        for (int i = converters.size() - 1; i >= 0; i--) {
            if (converters.get(i) instanceof MappingJackson2HttpMessageConverter) {
                converters.remove(i);
            }
        }
        FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();

        //自定义fastjson配置

        FastJsonConfig config = new FastJsonConfig();
        config.setSerializerFeatures(

                SerializerFeature.WriteMapNullValue,        // 是否输出值为null的字段,默认为false,我们将它打开
                SerializerFeature.WriteNullListAsEmpty,     // 将Collection类型字段的字段空值输出为[]
                SerializerFeature.WriteNullStringAsEmpty,   // 将字符串类型字段的空值输出为空字符串
                SerializerFeature.WriteNullNumberAsZero,    // 将数值类型字段的空值输出为0
                SerializerFeature.PrettyFormat,             //结果是否格式化,默认为false
                SerializerFeature.WriteDateUseDateFormat,     //解决反序列化时时间格式问题
                SerializerFeature.DisableCircularReferenceDetect    // 禁用循环引用

        );

        config.setSerializeFilters(new ValueFilter() {
            // Map<class,Map<filed,dateFormat>>
            Map<Class, Map<String, String>> dateFormatCache = new ConcurrentHashMap<>();

            //遍历所有的返回值,修改返回值的格式
            @Override
            public Object process(Object obj, String key, Object value) {

                if (value instanceof Date) {
                    Class<?> objClass = obj.getClass();
                    if (dateFormatCache.get(objClass) == null) {
                        dateFormatCache.putIfAbsent(objClass, new HashMap<>());
                        Map<String, String> newFormatMap = dateFormatCache.get(objClass);
                        ReflectionUtils.doWithFields(obj.getClass(), (field) -> {
                            if (field.getType() == Date.class) {
                                JSONField annotation = field.getAnnotation(JSONField.class);
                                if (annotation != null) {
                                    String format = annotation.format();
                                    if (StringUtils.isNotEmpty(format)) {
                                        newFormatMap.putIfAbsent(field.getName(), format);
                                    }
                                }
                            }
                        });
                    }

                    Map<String, String> dateFormatMap = dateFormatCache.get(objClass);
                    if (!dateFormatMap.isEmpty()) {
                        String format = dateFormatMap.get(key);
                        if(StringUtils.isNotEmpty(format)) {
                            SimpleDateFormat sdf = new SimpleDateFormat(format);
                            return sdf.format(value);
                        }
                    }
                }
                return value;
            }
        });

        fastJsonHttpMessageConverter.setFastJsonConfig(config);

        // 添加支持的MediaTypes;不添加时默认为*/*,也就是默认支持全部
        // 但是MappingJackson2HttpMessageConverter里面支持的MediaTypes为application/json
        // 参考它的做法, fastjson也只添加application/json的MediaType
        List<MediaType> fastMediaTypes = new ArrayList<>();
        fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
        fastJsonHttpMessageConverter.setSupportedMediaTypes(fastMediaTypes);
        converters.add(fastJsonHttpMessageConverter);

        //long返回给前端转换为String
        SerializeConfig serializeConfig = config.getSerializeConfig();
        serializeConfig.put(Long.class, ToStringSerializer.instance);
        serializeConfig.put(Long.TYPE, ToStringSerializer.instance);


    }

}